home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / fs / device.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  9KB  |  278 lines

  1. /* When a needed block is not in the cache, it must be fetched from the disk.
  2.  * Special character files also require I/O.  The routines for these are here.
  3.  *
  4.  * The entry points in this file are:
  5.  *   dev_open:     called when a special file is opened
  6.  *   dev_close:  called when a special file is closed
  7.  *   dev_io:     perform a read or write on a block or character device
  8.  *   do_ioctl:     perform the IOCTL system call
  9.  *   rw_dev:     procedure that actually calls the kernel tasks
  10.  *   rw_dev2:     procedure that actually calls task for /dev/tty
  11.  *   no_call:     dummy procedure (e.g., used when device need not be opened)
  12.  *   tty_open:   a tty has been opened
  13.  *   tty_exit:   a process with pid=pgrp has exited.
  14.  */
  15.  
  16. #include "fs.h"
  17. #include <minix/com.h>
  18. #include "dev.h"
  19. #include "file.h"
  20. #include "fproc.h"
  21. #include "inode.h"
  22. #include "param.h"
  23.  
  24. PRIVATE message dev_mess;
  25. PRIVATE major, minor, task;
  26.  
  27. FORWARD void find_dev();
  28.  
  29. /*===========================================================================*
  30.  *                dev_open                     *
  31.  *===========================================================================*/
  32. PUBLIC int dev_open(rip, mod, nonblock)
  33. struct inode *rip;        /* pointer to the inode */
  34. int mod;            /* how to open it */
  35. int nonblock;            /* TRUE if nonblocking open */
  36. {
  37. /* Special files may need special processing upon open. */
  38.  
  39.   dev_t dev;
  40.  
  41.   if (rip->i_count > 1) return(OK);
  42.   dev = (dev_t) rip->i_zone[0];    /* device type */
  43.   find_dev(dev);
  44.   dev_mess.DEVICE = dev;
  45.   (*dmap[major].dmap_open)(task, &dev_mess);
  46.   return(dev_mess.REP_STATUS);
  47. }
  48.  
  49.  
  50. /*===========================================================================*
  51.  *                dev_close                     *
  52.  *===========================================================================*/
  53. PUBLIC void dev_close(rip)
  54. struct inode *rip;        /* ptr to the inode */
  55. {
  56. /* This procedure can be used when a special file needs to be closed. */
  57.  
  58.   dev_t dev;            /* which device to close */
  59.  
  60.   if (rip->i_count > 1) return;
  61.   dev = (dev_t) rip->i_zone[0];
  62.   find_dev(dev);
  63.   (*dmap[major].dmap_close)(task, &dev_mess);
  64. }
  65.  
  66.  
  67. /*===========================================================================*
  68.  *                dev_io                         *
  69.  *===========================================================================*/
  70. PUBLIC int dev_io(rw_flag, nonblock, dev, pos, bytes, proc, buff)
  71. int rw_flag;            /* READING or WRITING */
  72. int nonblock;            /* TRUE if nonblocking op */
  73. dev_t dev;            /* major-minor device number */
  74. off_t pos;            /* byte position */
  75. int bytes;            /* how many bytes to transfer */
  76. int proc;            /* in whose address space is buff? */
  77. char *buff;            /* virtual address of the buffer */
  78. {
  79. /* Read or write from a device.  The parameter 'dev' tells which one. */
  80.  
  81.   find_dev(dev);
  82.  
  83.   /* Set up the message passed to task. */
  84.   dev_mess.m_type   = (rw_flag == READING ? DISK_READ :
  85.                rw_flag == WRITING ? DISK_WRITE : rw_flag);
  86.   dev_mess.DEVICE   = (dev >> MINOR) & BYTE;
  87.   dev_mess.POSITION = pos;
  88.   dev_mess.PROC_NR  = proc;
  89.   dev_mess.ADDRESS  = buff;
  90.   dev_mess.COUNT    = bytes;
  91.   dev_mess.TTY_FLAGS = nonblock; /* temporary kludge */
  92.  
  93.   /* Call the task. */
  94.   (*dmap[major].dmap_rw)(task, &dev_mess);
  95.  
  96.   /* Task has completed.  See if call completed. */
  97.   if (dev_mess.REP_STATUS == SUSPEND) suspend(task);    /* suspend user */
  98.  
  99.   return(dev_mess.REP_STATUS);
  100. }
  101.  
  102.  
  103. /*===========================================================================*
  104.  *                do_ioctl                     *
  105.  *===========================================================================*/
  106. PUBLIC int do_ioctl()
  107. {
  108. /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
  109.  
  110.   struct filp *f;
  111.   register struct inode *rip;
  112.  
  113.   if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
  114.   rip = f->filp_ino;        /* get inode pointer */
  115.   if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) return(ENOTTY);
  116.   find_dev(rip->i_zone[0]);
  117.  
  118.   dev_mess.m_type  = TTY_IOCTL;
  119.   dev_mess.PROC_NR = who;
  120.   dev_mess.TTY_LINE = minor;    
  121.   dev_mess.TTY_REQUEST = m.TTY_REQUEST;
  122.   dev_mess.TTY_SPEK = m.TTY_SPEK;
  123.   dev_mess.TTY_FLAGS = m.TTY_FLAGS;
  124.   /* Call the task. */
  125.   (*dmap[major].dmap_rw)(task, &dev_mess);
  126.  
  127.   /* Task has completed.  See if call completed. */
  128.   if (dev_mess.m_type == SUSPEND) suspend(task);  /* User must be suspended. */
  129.   m1.TTY_SPEK = dev_mess.TTY_SPEK;    /* erase and kill */
  130.   m1.TTY_FLAGS = dev_mess.TTY_FLAGS;    /* flags */
  131.   return(dev_mess.REP_STATUS);
  132. }
  133.  
  134.  
  135. /*===========================================================================*
  136.  *                find_dev                     *
  137.  *===========================================================================*/
  138. PRIVATE void find_dev(dev)
  139. dev_t dev;            /* device */
  140. {
  141. /* Extract the major and minor device number from the parameter. */
  142.  
  143.   major = (dev >> MAJOR) & BYTE;    /* major device number */
  144.   minor = (dev >> MINOR) & BYTE;    /* minor device number */
  145.   if (major == 0 || major >= max_major) panic("bad major dev", major);
  146.   task = dmap[major].dmap_task;    /* which task services the device */
  147. }
  148.  
  149.  
  150. /*===========================================================================*
  151.  *                rw_dev                         *
  152.  *===========================================================================*/
  153. PUBLIC void rw_dev(task_nr, mess_ptr)
  154. int task_nr;            /* which task to call */
  155. message *mess_ptr;        /* pointer to message for task */
  156. {
  157. /* All file system I/O ultimately comes down to I/O on major/minor device
  158.  * pairs.  These lead to calls on the following routines via the dmap table.
  159.  */
  160.  
  161.   int r;
  162.   message m;
  163.  
  164.   while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
  165.     /* sendrec() failed to avoid deadlock. The task 'task_nr' is
  166.      * trying to send a REVIVE message for an earlier request.
  167.      * Handle it and go try again.
  168.      */
  169.     if (receive(task_nr, &m) != OK) panic("rw_dev: can't receive", NO_NUM);
  170.  
  171.     /* If we're trying to send a cancel message to a task which has just
  172.      * sent a completion reply, ignore the reply and abort the cancel
  173.      * request. The caller will do the revive for the process. 
  174.      */
  175.     if (mess_ptr->m_type == CANCEL && m.REP_PROC_NR == mess_ptr->PROC_NR)
  176.         return;
  177.     revive(m.REP_PROC_NR, m.REP_STATUS);
  178.   }
  179.   if (r != OK) panic("rw_dev: can't send", NO_NUM);
  180. }
  181.  
  182.  
  183. /*===========================================================================*
  184.  *                rw_dev2                         *
  185.  *===========================================================================*/
  186. PUBLIC void rw_dev2(dummy, mess_ptr)
  187. int dummy;            /* not used - for compatibility with rw_dev() */
  188. message *mess_ptr;        /* pointer to message for task */
  189. {
  190. /* This routine is only called for one device, namely /dev/tty.  Its job
  191.  * is to change the message to use the controlling terminal, instead of the
  192.  * major/minor pair for /dev/tty itself.
  193.  */
  194.  
  195.   int task_nr, major_device;
  196.  
  197.   if (fp->fs_tty == 0) {
  198.     mess_ptr->DEVICE = NULL_DEV;
  199.     rw_dev(MEM, mess_ptr);
  200.     return;
  201.   }
  202.   major_device = (fp->fs_tty >> MAJOR) & BYTE;
  203.   task_nr = dmap[major_device].dmap_task;    /* task for controlling tty */
  204.   mess_ptr->DEVICE = (fp->fs_tty >> MINOR) & BYTE;
  205.   rw_dev(task_nr, mess_ptr);
  206. }
  207.  
  208.  
  209. /*===========================================================================*
  210.  *                no_call                         *
  211.  *===========================================================================*/
  212. PUBLIC void no_call(task_nr, m_ptr)
  213. int task_nr;            /* which task */
  214. message *m_ptr;            /* message pointer */
  215. {
  216. /* Null operation always succeeds. */
  217.  
  218.   m_ptr->REP_STATUS = OK;
  219. }
  220.  
  221. /*===========================================================================*
  222.  *                tty_open                     *
  223.  *===========================================================================*/
  224. PUBLIC void tty_open(task_nr, mess_ptr)
  225. int task_nr;
  226. message *mess_ptr;
  227. {
  228.   register struct fproc *rfp;
  229.   int maj;
  230.  
  231.   mess_ptr->REP_STATUS = OK;
  232.  
  233.   /* Is this a process group leader? */
  234.   if (fp->fp_pid != fp->fp_pgrp) return;
  235.  
  236.   /* Is there a current control terminal? */
  237.   if (fp->fs_tty != 0) return;
  238.  
  239.   /* Is this one already allocated to another process? */
  240.   for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
  241.     if (rfp->fs_tty == mess_ptr->DEVICE) return;
  242.  
  243.   /* All conditions satisfied.  Make this a control terminal. */
  244.   fp->fs_tty = mess_ptr->DEVICE;
  245.   maj = (mess_ptr->DEVICE >> MAJOR) & BYTE;
  246.   mess_ptr->DEVICE = (mess_ptr->DEVICE >> MIN